const fs = require('fs');
let ncp = require('ncp'); // 用于copy文件
const axios = require('axios');
const path = require('path');
const { promisify } = require('util');
const inquirer = require('inquirer');
const ora = require('ora');  // loading提示
let downloadFn = require('download-git-repo'); // 下载git pro
let Metalsmith = require('metalsmith');
let { render } = require('consolidate').ejs; // consolidate为多模板语言的集合
const { rejects } = require('assert');


downloadFn = promisify(downloadFn); // 让 downloadFn 支持async + await   



// 工具方法：添加耗时等待
const addLoading = function (fn) {

    return async function (...args) {
        const spinner = ora('拉取开始....');
        spinner.start();
        try {
            let ret = await fn(...args);
            spinner.succeed('拉取成功')
            return ret;
        } catch (error) {
            console.log(error)
            spinner.fail('拉取失败');
        }
    }

}
// 工具方法：获取仓库列表
const fetchRepoList = async function () {
    const { data } = await axios.get('https://api.github.com/users/zcegg/repos')
    const repos = data.map(item => item.name)
    return repos;
}

// 工具方法：获取 tags 列表
const fetchTagList = async function (tmpname) {
    const { data } = await axios.get(`https://api.github.com/repos/zcegg/${tmpname}/tags`)
    const repos = data.map(item => item.name)
    return repos;
}

// 工具方法：自定义函数完成 git 仓库下载操作
const downloadRepo = async function (repo, tag) {
    // download-git-repo + 缓存
    //1 定义缓存目录
    let cacheDir = `${process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME']}/.tmp`

    // 2 处理download-git-repo 函数的调用规则 downloadFn(zcegg/create-nm#tagv)
    let cachePro = tag ? `${repo}#${tag}` : repo
    let api = `zcegg/${cachePro}`


    // 3 定义一个模板下载后的输出路径
    // let dest = path.resolve(cacheDir, repo);     console.warn('这里还存在一个问题 dest输出路径没有考虑版本的问题,待优化');
    let dest = path.resolve(cacheDir, cachePro);

    //判断缓存中是否已经存在
    const flag = fs.existsSync(dest)

    if (!flag) {
        // 4 执行下载操作
        await addLoading(downloadFn)(api, dest);
    }

    // 5 将设置好的缓存目录返回
    return dest;
}


module.exports = async (pramas) => {

    //1 获取模板列表
    const repos = await addLoading(fetchRepoList)();

    //2 交互问题
    let { tmpname } = await inquirer.prompt({
        type: 'list',
        name: 'tmpname',
        message: '请选择目标仓库模板',
        choices: repos,
    })
    console.log(tmpname);

    //3 拉取 tags ， tags可能为有值数组或空数组
    const tags = await addLoading(fetchTagList)(tmpname);

    console.log(tags);


    // 4 tags分支处理 [v1,v2,v3.....]  []
    let dest = null;
    if (tags.length) {
        // 仓库存在多个tag
        let { tagv } = await inquirer.prompt({
            type: 'list',
            name: 'tagv',
            message: '请选择目标版本',
            choices: tags,
        })
        console.log(tagv);

        // 4.1 w根据选择的模板名称和仓库的版本号完成具体的下载操作
        dest = await downloadRepo(tmpname, tagv)
        console.log(dest);
    } else {
        //  仓库不存在多个 tags 版本
        let { isDownload } = await inquirer.prompt({
            type: 'confirm',
            name: 'isDownload',
            message: '当前不存在多个tag是否直接下载',
        })

        if (isDownload) {
            console.log('选择yes直接执行下载操作');
            dest = await downloadRepo(tmpname)
            console.log(dest);
        } else {
            return;
        }
    }


    /**
     * 5 将文件下载完成之后在本地缓存中存在着具体的文件
     *   利用这些文件可以初始化我们的项目
     * 
     * 两种吧情况：一种情况是项目初始化过程中需要用户动态提供数据
     *           另一种情况是项目中不需要动态渲染数据，直接下载即可
     * 
     * 
     */


    let proname = (Array.isArray(pramas) && pramas.length > 0) ? pramas[0] : 'proname'

    // que.js 提前提供的项目中需要动态提供的数据问题文件
    if (fs.existsSync(path.join(dest, 'que.js'))) {
        // 当前需要渲染数据
        await new Promise((resolve, reject) => {
            Metalsmith(__dirname)
                .source(dest)
                .destination(path.resolve(proname))
                .use((files, metal, done) => {
                    console.log(files);
                    done();
                })
                .use((files, metal, done) => {
                    done();
                })
                .build((error) => {
                    if (error) {
                        reject()
                    } else {
                        resolve()
                    }
                })
        })

    } else {
        // 当前不需要渲染数据
        // 直接将缓存中的文件拷贝到当前目录下

        console.log(dest);
        console.log(proname);

        ncp(dest, proname);

    }

}


